package mobi.weq.util;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;

import mobi.weq.db.Database;
import mobi.weq.model.Observation;
import mobi.weq.model.SensorObservation;

public class Generator {

	public static void main(String[] args) {
		// printEdinburghStatistics("co");
		// printEdinburghStatistics("o3");
		// printEdinburghStatistics("no2");
		// printEdinburghStatistics("pm10");
		// printEdinburghStatistics("pm2p5");
		// printEdinburghStatistics("so2");
		// int time = new Date().getHours();
		// for (int i = 0; i < 60; i++) {
		// time = ((time - 1) + 24) % 24;
		// System.out.println(time);
		// }
		// generateEdinburghObservations(4);
		// System.out.println(generateEdinburghLatitude());

	}

	public static ArrayList<Observation> generateEdinburghObservations(
			int lastNDays) {
		Date d = new Date();
		d.setMinutes(0);
		d.setSeconds(0);
		ArrayList<Observation> observations = new ArrayList<Observation>();
		int total = lastNDays * 24;
		int time = d.getHours();
		for (int i = 0; i < total; i++) {
			Observation o = generateEdinburghObservation(d);
			observations.add(o);
			d = Util.decreaseDateByHour(d, 1);
		}
		return observations;
	}

	public static ArrayList<SensorObservation> generateEdinburghSensorObservations(
			int lastNDays) {
		Date d = new Date();
		d.setMinutes(0);
		d.setSeconds(0);
		ArrayList<SensorObservation> observations = new ArrayList<SensorObservation>();
		int total = lastNDays * 24;
		int time = d.getHours();
		for (int i = 0; i < total; i++) {
			SensorObservation o = generateEdinburghSensorObservation(d);
			observations.add(o);
			d = Util.decreaseDateByHour(d, 1);
		}
		return observations;
	}

	// public static Observation generateEdinburghObservation(Date d) {
	// Observation o = new Observation();
	// }
	public static Observation generateEdinburghObservation(Date d) {
		Observation o = new Observation();
		int time = d.getHours();
		o.setDatetime(d);
		o.setCo(edinburghCOGenerator(time));
		o.setO3(edinburghO3Generator(time));
		o.setPm10(edinburghPM10Generator(time));
		o.setPm2p5(edinburghPM2P5Generator(time));
		o.setSo2(edinburghSO2Generator(time));
		o.setNo2(edinburghNO2Generator(time));
		return o;
	}

	public static SensorObservation generateEdinburghSensorObservation(Date d) {
		SensorObservation o = new SensorObservation();
		int time = d.getHours();
		o.setTimestamp(d);
		o.setCity("Edinburgh");
		o.setO3(edinburghO3Generator(time));
		o.setPm10(edinburghPM10Generator(time));
		o.setPm2p5(edinburghPM2P5Generator(time));
		o.setSo2(edinburghSO2Generator(time));
		o.setNo2(edinburghNO2Generator(time));
		return o;
	}

	public static double getGaussian(double mean, double variance) {
		Random random = new Random();
		return mean + random.nextGaussian() * variance;
	}

	public static double edinburghCOGenerator(int time) {
		// using EdinburghPollutionSubstanceStatistics
		Random random = new Random();
		Double mean = PollutionSubstanceStatistics.coMap.get(time).get(0);// mean
																			// from
																			// EdinburghPollutionSubstanceStatistics.coMap
		Double variance = PollutionSubstanceStatistics.coMap.get(time).get(1);// variance
																				// from
																				// EdinburghPollutionSubstanceStatistics.coMap
		return mean + random.nextGaussian() * variance;// generating gaussian
														// random number, so
														// that it is close to
														// real data.
		// you got it?
	}

	public static double edinburghNO2Generator(int time) {
		Random random = new Random();
		Double mean = PollutionSubstanceStatistics.no2Map.get(time).get(0);
		Double variance = PollutionSubstanceStatistics.no2Map.get(time).get(1);
		return mean + random.nextGaussian() * variance;
	}

	public static double edinburghSO2Generator(int time) {
		Random random = new Random();
		Double mean = PollutionSubstanceStatistics.so2Map.get(time).get(0);
		Double variance = PollutionSubstanceStatistics.so2Map.get(time).get(1);
		return mean + random.nextGaussian() * variance;
	}

	public static double edinburghO3Generator(int time) {
		Random random = new Random();
		Double mean = PollutionSubstanceStatistics.o3Map.get(time).get(0);
		Double variance = PollutionSubstanceStatistics.o3Map.get(time).get(1);
		return mean + random.nextGaussian() * variance;
	}

	public static double edinburghPM10Generator(int time) {
		Random random = new Random();
		Double mean = PollutionSubstanceStatistics.pm10Map.get(time).get(0);
		Double variance = PollutionSubstanceStatistics.pm10Map.get(time).get(1);
		return mean + random.nextGaussian() * variance;
	}

	public static double edinburghPM2P5Generator(int time) {
		Random random = new Random();
		Double mean = PollutionSubstanceStatistics.pm2p5Map.get(time).get(0);
		Double variance = PollutionSubstanceStatistics.pm2p5Map.get(time)
				.get(1);
		return mean + random.nextGaussian() * variance;
	}

	public static void printEdinburghStatistics(String substance) {
		try {
			Connection c = Database.getConnection();
			String query = "select ("
					+ substance
					+ "-avg("
					+ substance
					+ "))*("
					+ substance
					+ "-avg("
					+ substance
					+ "))/count(*) as variance, avg("
					+ substance
					+ "), extract(hour from time_stamp) from observation group by 3;";

			System.out.println(query);
			PreparedStatement ps = c.prepareStatement(query);
			ResultSet result = ps.executeQuery();
			HashMap<Integer, ArrayList<Double>> map = new HashMap<Integer, ArrayList<Double>>();
			System.out.println("HashMap<Integer, ArrayList<Double>> "
					+ substance
					+ "Map = new HashMap<Integer, ArrayList<Double>>(){{");
			while (result.next()) {
				double variance = result.getDouble(1);
				double mean = result.getDouble(2);
				double time = result.getDouble(3);
				ArrayList<Double> list = new ArrayList<Double>();
				list.add(mean);
				list.add(variance);
				map.put((int) time, list);
				System.out.println("put(Integer.valueOf(" + (int) time
						+ "),new ArrayList<Double>() {{");
				System.out.println("add(Double.valueOf(" + mean + "));");
				System.out.println("add(Double.valueOf(" + variance + "));");
				System.out.println("}});");
			}
			System.out.println("}};");
			// System.out.println(map);
		} catch (Exception e) {
			System.out.println(e);
		}
	}

	public static double generateEdinburghLatitude() {
		double k = 55.940778962167435, j = 55.9413520357129;
		double diff = k - j;
		Random r = new Random();
		return r.nextDouble() * diff + j;
	}

	public static double generateEdinburghLongitude() {
		double j = -3.2064564836059617, k = -3.2043107163940476;
		double diff = k - j;
		Random r = new Random();
		return r.nextDouble() * diff + j;
	}

	public static Observation generateEdinburghCurrentObservation() {
		return generateEdinburghObservation(new Date());
	}

}
